package text

func (b *Buffer) dokbd() {
	for {
		key := <-b.KeyboardChan

		// fix left, right, and up on OSX
		if (key & 0xff00) == 0xf000 {
			key = key & 0xff
		}

		switch key {
		// backspace
		case 8:
			b.backspace()
			b.PushState()

		// return
		case 10:
			b.newline()

		// up
		case 14:
			b.scroll(-18)
			b.PushState()

		// page up
		case 15:
			b.scroll(-40)
			b.PushState()

		// left
		case 17:
			b.left()
			b.PushState()

		// right
		case 18:
			b.right()
			b.PushState()

		// page down
		case 19:
			b.scroll(40)
			b.PushState()

		// down
		case 128:
			b.scroll(18)
			b.PushState()

		// cmd-c
		case 61795:
			b.snarf(b.getsel())
			b.PushState()

		// cmd-v
		case 61814:
			b.paste()
			b.PushState()

		// cmd-x
		case 61816:
			b.snarf(b.getsel())
			b.deletesel()
			b.PushState()

		default:
			b.input(rune(key))
		}

		// Every keyboard interaction requires a redraw.
		b.redraw()
	}
}

func (b *Buffer) backspace() {
	b.deletesel()
	left := b.Dot.Left
	x, y := left.X, left.Y
	if x > 0 {
		b.lines[y].dirty = true
		left.X--
		line := b.lines[y].s
		line = append(line[:left.X], line[left.X+1:]...)
		b.lines[y].s = line
	} else if y > 0 {
		left.Y--
		y--
		b.lines[y].dirty = true
		left.X = len(b.lines[y].s)

		// delete the old line
		b.lines[y].s = append(b.lines[y].s, b.lines[y+1].s...)
		b.lines = append(b.lines[:y+1], b.lines[y+2:]...)
	}
	b.Dot.Left, b.Dot.Right = left, left
}

func (b *Buffer) left() {
	b.Dot.selection = selNone
	left := b.Dot.Left
	if left.X > 0 {
		left.X--
	} else if left.Y > 0 {
		left.Y--
		left.X = len(b.lines[left.Y].s)
	}
	b.Dot.Left, b.Dot.Right = left, left
}

func (b *Buffer) right() {
	b.Dot.selection = selNone
	left := b.Dot.Left
	if left.X < len(b.lines[left.Y].s) {
		left.X++
	} else if left.Y < len(b.lines)-1 {
		left.Y++
		left.X = 0
	}
	b.Dot.Left, b.Dot.Right = left, left
}

func (b *Buffer) newline() {
	b.deletesel()
	x, y := b.Dot.Left.X, b.Dot.Left.Y
	nl := &line{
		s:     make([]rune, 0, 100),
		dirty: true,
	}
	b.lines[y].dirty = true
	if x == len(b.lines[y].s) && y == len(b.lines)-1 {
		// easy case, dot is at the end of the final line
		b.lines = append(b.lines, nl)
	} else {
		// insert a new line at y+1
		b.lines = append(b.lines, nil)
		copy(b.lines[y+2:], b.lines[y+1:])
		b.lines[y+1] = nl

		// update strings for the y+1 and y
		b.lines[y+1].s = b.lines[y].s[x:]
		b.lines[y].s = b.lines[y].s[:x]
	}
	b.Dot.Left.X = 0
	b.Dot.Left.Y++
	b.Dot.Right = b.Dot.Left
}
